/*!
 * \file memcached_core.c
 *
 * \brief 共通定义
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 共通使用的宏和结构体
 *
 * \version 1.0
 * \author jikw
 * \date 2015/10/14
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"
#include "frreport_comm.h"
#include "frct_comm.h"
#include "frservice_comm.h"
#include "frbyte_buffer.h"
#include "frct_detect_hash.h"
#include "memcached_core.h"

#define MEMCACHED_DETECT_ONCE 1                       //经过一次detect判断成功
#define MEMCACHED_DETECT_TWICE 2                      //经过两次detect判断成功

extern void *g_p_apm_context;

typedef struct __st_L7session_memcached_private
{
    unsigned long ul_seq;                             //序列号，1次req和response时，使用同一个序列号
    L4_transaction st_l4_trans;                       //数据
    Frreport_body_data *p_st_body_data_req;
    Frreport_body_data *p_st_body_data_resp;
    Frlist_header *p_lst_comm;
    Frlist_header *p_lst_req;
    Frbyte_Packet *p_req_packet;                      //存请求bytebuff数据
    Frbyte_Packet *p_resp_packet;                     //存相应bytebuff数据
    int i_sign_get;                                   //标志位，1:为取回命令
    int i_sign_gets;
    int i_sign_stats;                                 //标志位，1:为状态命令
}L7session_memcached_private;

typedef struct __st_memcached_hash_detect_data
{
    int i_flag;                                       //标志位，1:经过一次detect判断成功 2:经过两次detect判断成功
}hash_detect_data;

/*
 * memcached私有数据创建
 *
 * \param void
 *
 * \return NULL          内存分配失败\n
 *         p_st_private  内存分配成功
 *
 * \note
 *
 */
FR_STATIC L7session_memcached_private* __memcached_private_create(void)
{
    L7session_memcached_private *p_st_private = NULL;

    p_st_private = (L7session_memcached_private*)frmalloc(sizeof(L7session_memcached_private));
    if (p_st_private == NULL)
        return NULL;

    memset(p_st_private, 0x00, sizeof(L7session_memcached_private));
    return p_st_private;
}

/*!
 * 私有信息重置
 *
 * \param p_private_session  (memcached的私有session数据)
 *
 * \return FR_SUCC   成功\n
 *
 * \note
 *
 */
FR_STATIC int __memcached_session_reset(void *p_private_session)
{
    L7session_memcached_private *p_st_private = (L7session_memcached_private*)p_private_session;

    if (p_st_private)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if (p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if (p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if (p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if (p_st_private->p_req_packet)
            bytebuff_free(&p_st_private->p_req_packet);

        if (p_st_private->p_resp_packet)
            bytebuff_free(&p_st_private->p_resp_packet);

        p_st_private->i_sign_stats = 0;
        p_st_private->i_sign_gets = 0;
        p_st_private->i_sign_get = 0;
    }
    return FR_SUCC;
}

/*!
 * 判断是否是memcached协议
 *
 * \param p_st_conn      (输入数据信息)
 * \param p_st_packet    (输入数据)
 *
 * \return APM_L7_IS_YES  属于memcached协议\n
 *         APM_L7_IS_NO   不属于memcached协议
 *
 * \note
 *
 */
int memcached_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret = 0;
    int i_ret_fun = 0;
    Frlist_node *p_node = NULL;
    hash_detect_data *p_detect_data = NULL;
    hash_detect_data *p_detect_data_get = NULL;
    Frct_detect_hash *p_st_ct_detect = NULL;

    if (p_st_packet == NULL || p_st_packet->p_payload == NULL || p_st_packet->ui_payload_len == 0 || p_st_conn==NULL)
        return APM_L7_IS_NO;

    //以这几种情况开头
    if (strncmp(p_st_packet->p_payload, "flush_all\r\n", p_st_packet->ui_payload_len) != 0 &&
        strncmp(p_st_packet->p_payload, "version\r\n", p_st_packet->ui_payload_len) != 0 &&
        strncmp(p_st_packet->p_payload, "quit\r\n", p_st_packet->ui_payload_len) != 0 &&
        strncmp(p_st_packet->p_payload, "stats\r\n", p_st_packet->ui_payload_len) != 0 &&
        strncmp(p_st_packet->p_payload, "delete ", 7) != 0 &&
        strncmp(p_st_packet->p_payload, "incr ", 5) != 0 &&
        strncmp(p_st_packet->p_payload, "decr ", 5) != 0 &&
        strncmp(p_st_packet->p_payload, "get ", 4) != 0 &&
        strncmp(p_st_packet->p_payload, "gets ", 5) != 0 &&
        strncmp(p_st_packet->p_payload, "replace ", 8) != 0 &&
        strncmp(p_st_packet->p_payload, "set ", 4) != 0 &&
        strncmp(p_st_packet->p_payload, "add ", 4) != 0 &&
        strncmp(p_st_packet->p_payload, "stats ", 6) != 0)
    {
        goto error;
    }

    //以\r\n结尾
    if (strncmp(p_st_packet->p_payload+p_st_packet->ui_payload_len-2, "\r\n", 2)!=0)
        goto error;

    p_node = frct_detect_data_get_node(p_st_conn, MODULE_L7PROTO);
    //第一次detect
    if (p_node == NULL)
    {
        p_detect_data = (hash_detect_data *)frmalloc(sizeof(hash_detect_data));
        if (p_detect_data == NULL)
            return APM_L7_IS_NO;
        p_detect_data->i_flag = MEMCACHED_DETECT_ONCE;
        frct_detect_hash_add(p_st_conn, MODULE_L7PROTO, (void *)p_detect_data);
        return APM_L7_IS_NO;
    }
    p_st_ct_detect = (Frct_detect_hash *)p_node->data;
    p_detect_data_get = (hash_detect_data *)p_st_ct_detect->p_detect_data;
    //第二次detect
    if (p_detect_data_get->i_flag == MEMCACHED_DETECT_ONCE)
    {
        p_detect_data_get->i_flag = MEMCACHED_DETECT_TWICE;
        return APM_L7_IS_NO;
    }
    //多次判断后
    if (p_detect_data_get->i_flag == MEMCACHED_DETECT_TWICE)
    {
        frct_detect_hash_del(p_st_conn, MODULE_L7PROTO);

        i_ret_fun = frct_get_direct_known(p_st_conn);
        if (i_ret_fun == FR_DIRECT_UNKNOWN)
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
        frservice_add(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0);
        return APM_L7_IS_YES;
    }

    return APM_L7_IS_NO;

error:
    if (frct_get_direct_known(p_st_conn) == FR_DIRECT_UNKNOWN)
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
            return APM_L7_IS_YES;
        }
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->src_ip, p_st_packet->src_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
        {
            frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            return APM_L7_IS_YES;
        }
    }
    else
    {
        i_ret = frservice_get(g_p_apm_context, MODULE_L7PROTO, p_st_packet->dst_ip, p_st_packet->dst_port, NULL, 0, NULL);
        if (i_ret == FR_SUCC)
            return APM_L7_IS_YES;
    }
    return APM_L7_IS_NO;
}

/*!
 * req数据解析
 *
 * \param p_packet        (req数据)
 * \param p_st_private    (私有数据)
 * \param p_st_body_data
 * \param p_st_conn       (入力链接信息)
 *
 * \return APM_L7_ANALYZE_SUCC   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __req_parse(Frbyte_Packet *p_packet
                        , L7session_memcached_private *p_st_private
                        , Frreport_body_data *p_st_body_data
                        , Conntrack *p_st_conn)
{
    int i_count = 0;
    int i_index1 = 0;
    int i_index2 = 0;
    int i_len_tmp = 0;
    char *p_value = NULL;
    char arr_cmd[8];
    char arr_len[8];

    if (p_packet == NULL || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    memset(arr_cmd, 0x00, sizeof(arr_cmd));
    memset(arr_len, 0x00, sizeof(arr_len));

    //有空格
    if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, " ", 1, &i_index1) != FR_FAIL)
    {
        //request有空格时，cmd长度最大为7
        if (i_index1 > 7)
            goto ERROR;

        if (bytebuff_peek_bytes(p_packet, arr_cmd, i_index1) == FR_FAIL)
            goto ERROR;
        //命令上报
        if (frreport_body_l7_add_str(p_st_body_data, "request.memcached.cmd", arr_cmd) == FR_FAIL)
            goto ERROR;
        if (strcmp(arr_cmd, "get") == 0)
            p_st_private->i_sign_get = 1;
        if (strcmp(arr_cmd, "gets") == 0)
            p_st_private->i_sign_gets = 1;
        if (strcmp(arr_cmd, "stats") == 0)
            p_st_private->i_sign_stats = 1;

        if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, "\r\n", 2, &i_index2) == FR_FAIL)
            goto ERROR;
        p_value = (char *)frmalloc(i_index2+1);
        if (p_value == NULL)
            goto ERROR;
        memset(p_value, 0x00, i_index2+1);
        if (bytebuff_peek_bytes(p_packet, p_value, i_index2) == FR_FAIL)
            goto ERROR;
        frrtrim(p_value);
        if (frstrupper(p_value, i_index2) == FR_FAIL)
            goto ERROR;
        //title上报
        if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_value) == FR_FAIL)
            goto ERROR;
        frfree(p_value);
        p_value = NULL;

        //跳过“cmd ”
        if (bytebuff_skip(p_packet, i_index1+1) != FR_SUCC)
            goto ERROR;
        //参数长度
        i_len_tmp = i_index2-i_index1-1;
        if (i_len_tmp <= 0)
            goto ERROR;
        p_value = (char *)frmalloc(i_len_tmp+1);
        if (p_value == NULL)
            goto ERROR;
        memset(p_value, 0x00, i_len_tmp+1);
        if (bytebuff_peek_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
            goto ERROR;
        frrtrim(p_value);
        //参数上报
        if (frreport_body_l7_add_str(p_st_body_data, "request.memcached.param", p_value) == FR_FAIL)
            goto ERROR;

        if (strcmp(arr_cmd, "set") == 0 || strcmp(arr_cmd, "add") == 0 || strcmp(arr_cmd, "replace") == 0)
        {
            if (memchr(p_value, ' ', strlen(p_value)) == NULL)
                goto ERROR;
            i_count = 0;
            while(1)
            {
                if (*(p_value+strlen(p_value)-1-i_count) == ' ')
                    break;
                i_count++;
            }
            strcpy(arr_len, p_value+strlen(p_value)-i_count);
            frfree(p_value);
            p_value = NULL;
            i_len_tmp = atoi(arr_len);

            bytebuff_rewind(p_packet);
            //从参数后开始取data
            if (bytebuff_skip(p_packet, i_index2+2) != FR_SUCC)
                goto ERROR;
            if (bytebuff_remaining(p_packet) < i_len_tmp)
                return  APM_L7_ANALYZE_TODO;

            p_value = (char *)frmalloc(i_len_tmp+1);
            if (p_value == NULL)
                goto ERROR;
            memset(p_value, 0x00, i_len_tmp+1);
            if (bytebuff_get_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
                goto ERROR;
            if (fris_print_ascii(p_value, i_len_tmp)==0)
            {
                if (frreport_body_l7_add_bin(p_st_body_data, "request.memcached.data", p_value, i_len_tmp) == FR_FAIL)
                    goto ERROR;
            }
            else
            {
                if (frreport_body_l7_add_str(p_st_body_data, "request.memcached.data", p_value) == FR_FAIL)
                    goto ERROR;
            }
            frfree(p_value);
            return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);
        }
        frfree(p_value);
    }
    //无空格
    else
    {
        i_len_tmp = bytebuff_length(p_packet)-2;
        p_value = (char *)frmalloc(i_len_tmp+1);
        if (p_value == NULL)
            goto ERROR;
        memset(p_value, 0x00, i_len_tmp+1);
        if (bytebuff_peek_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
            goto ERROR;
        if (strcmp(p_value, "stats") == 0)
            p_st_private->i_sign_stats = 1;
        //cmd上报
        if (frreport_body_l7_add_str(p_st_body_data, "request.memcached.cmd", p_value) == FR_FAIL)
            goto ERROR;
        if (frstrupper(p_value, i_len_tmp) == FR_FAIL)
            goto ERROR;
        //title上报
        if (frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_value) == FR_FAIL)
            goto ERROR;
        frfree(p_value);
        p_value = NULL;
    }

    return APM_L7_ANALYZE_SET_REQ(APM_L7_ANALYZE_SUCC);

ERROR:
    if (p_value)
        frfree(p_value);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * resp数据解析
 *
 * \param p_packet        (resp数据)
 * \param p_st_private    (私有数据)
 * \param p_st_body_data
 * \param p_st_conn       (入力链接信息)
 *
 * \return APM_L7_ANALYZE_SUCC   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __resp_parse(Frbyte_Packet *p_packet
                         , L7session_memcached_private *p_st_private
                         , Frreport_body_data *p_st_body_data
                         , Conntrack *p_st_conn)
{
    int i_tmp = 0;
    int i_count = 0;
    int i_index1 = 0;
    int i_index2 = 0;
    int i_len_tmp = 0;
    char *p_value = NULL;
    char *p_pos = NULL, *p_pos2 = NULL, *p_pos3 = NULL;
    char arr_len[8];
    char arr_name[32];

    if (p_packet == NULL || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    memset(arr_len, 0x00, sizeof(arr_len));
    memset(arr_name, 0x00, sizeof(arr_name));

    if (p_st_private->i_sign_get == 1 || p_st_private->i_sign_stats == 1 || p_st_private->i_sign_gets == 1)
    {
        for (i_tmp = 0; ; i_tmp++)
        {
            //查找空格，肯定存在
            if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, " ", 1, &i_index1) == FR_FAIL)
                goto ERROR;
            //查找\r\n，肯定存在，且在空格以后
            if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, "\r\n", 2, &i_index2) == FR_FAIL)
                goto ERROR;
            //参数长度
            i_len_tmp = i_index2-i_index1-1;
            if (i_len_tmp <= 0)
                goto ERROR;
            p_value = (char *)frmalloc(i_len_tmp+1);
            if (p_value == NULL)
                goto ERROR;
            memset(p_value, 0x00, i_len_tmp+1);
            if (bytebuff_skip(p_packet, i_index1-bytebuff_getPosition(p_packet)+1) != FR_SUCC)
                goto ERROR;
            if (bytebuff_get_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
                goto ERROR;
            frrtrim(p_value);
            //参数上报
            snprintf(arr_name, sizeof(arr_name), "response.memcached.param.%d", i_tmp+1);
            if (frreport_body_l7_add_str(p_st_body_data, arr_name, p_value) == FR_FAIL)
                goto ERROR;

            if (bytebuff_skip(p_packet, 2) != FR_SUCC)
                goto ERROR;

            if (p_st_private->i_sign_get == 1 || p_st_private->i_sign_gets == 1)
            {
                if (p_st_private->i_sign_get == 1)
                {
                    if (memchr(p_value, ' ', strlen(p_value)) == NULL)
                        goto ERROR;
                    i_count = 0;
                    while(1)
                    {
                        if (*(p_value+strlen(p_value)-1-i_count) == ' ')
                            break;
                        i_count++;
                    }
                    strcpy(arr_len, p_value+strlen(p_value)-i_count);
                }
                else
                {
                    //第一个空格
                    p_pos = (char *)memchr(p_value, ' ', strlen(p_value));
                    if (p_pos == NULL)
                        goto ERROR;
                    //第二个空格
                    p_pos2 = (char *)memchr(p_pos+1, ' ', strlen(p_value)-(p_pos-p_value)-1);
                    if (p_pos2 == NULL)
                        goto ERROR;
                    //第三个空格
                    p_pos3 = (char *)memchr(p_pos2+1, ' ', strlen(p_value)-(p_pos2-p_value)-1);
                    if (p_pos3 == NULL)
                        goto ERROR;
                    strncpy(arr_len, p_pos2+1, p_pos3-p_pos2-1);
                }
                frfree(p_value);
                p_value = NULL;
                i_len_tmp = atoi(arr_len);
                if (bytebuff_remaining(p_packet) < i_len_tmp)
                    return  APM_L7_ANALYZE_TODO;
                p_value = (char *)frmalloc(i_len_tmp+1);
                if (p_value == NULL)
                    goto ERROR;
                memset(p_value, 0x00, i_len_tmp+1);
                //从参数后开始取data
                if (bytebuff_get_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
                    goto ERROR;
                snprintf(arr_name, sizeof(arr_name), "response.memcached.data.%d", i_tmp+1);
                if (fris_print_ascii(p_value, i_len_tmp)==0)
                {
                    if (frreport_body_l7_add_bin(p_st_body_data, arr_name, p_value, i_len_tmp) == FR_FAIL)
                        goto ERROR;
                }
                else
                {
                    if (frreport_body_l7_add_str(p_st_body_data, arr_name, p_value) == FR_FAIL)
                        goto ERROR;
                }
                //frfree(p_value);
                //p_value = NULL;
            }

            frfree(p_value);
            p_value = NULL;

            if (p_st_private->i_sign_get == 1 || p_st_private->i_sign_gets == 1)
            {
                if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, "VALUE ", 6, &i_index1) == FR_FAIL)
                    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }
            else
            {
                if (bytebuff_memstr(p_packet, bytebuff_getPosition(p_packet), 0, "STAT ", 5, &i_index1) == FR_FAIL)
                    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
            }
        }
    }

    //去除\r\n，全部上报为参数
    i_len_tmp = bytebuff_length(p_packet)-2;
    if (i_len_tmp <= 0)
        goto ERROR;
    p_value = (char *)frmalloc(i_len_tmp+1);
    if (p_value == NULL)
        goto ERROR;
    memset(p_value, 0x00, i_len_tmp+1);
    if (bytebuff_get_bytes(p_packet, p_value, i_len_tmp) == FR_FAIL)
        goto ERROR;
    if (frreport_body_l7_add_str(p_st_body_data, "response.memcached.param", p_value) == FR_FAIL)
        goto ERROR;
    frfree(p_value);
    return APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);

ERROR:
    if (p_value)
        frfree(p_value);

    return APM_L7_ANALYZE_FAIL;
}

/*!
 * memcached的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet       (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 * \param p_st_session       (私有数据)
 *
 * \return APM_L7_ANALYZE_SUCC   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __req_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_memcached_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;
    unsigned long ul_tmp = 0;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL || p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private = (L7session_memcached_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    //如果连续的两个request
    if (p_st_private->p_lst_comm)
        __memcached_session_reset((void *)(p_st_private));

    //创建数据链表
    if (p_st_private->p_st_body_data_req == NULL)
    {
        p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_req == NULL)
            goto ERROR;

        if (frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn) == FR_FAIL)
            goto ERROR;

        //seq ++
        p_st_private->ul_seq = frct_seq_increase(p_st_conn);

        if (p_st_l4_trans->st_request_time_first_byte.tv_sec==0 && p_st_l4_trans->st_request_time_first_byte.tv_usec==0)
        {
            //st_request_time_first_byte
            p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
        }

        //创建bytebuff
        if (p_st_private->p_req_packet == NULL)
        {
            p_st_private->p_req_packet = bytebuff_creat();
            if (p_st_private->p_req_packet == NULL)
                goto ERROR;
        }
    }

    /* 请求的字节数 */
    p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

    if (p_st_private->p_req_packet == NULL)
        goto ERROR;
    //把这个包的数据全加进bytebuff里
    if (bytebuff_add(p_st_private->p_req_packet, p_st_packet->p_payload, p_st_packet->ui_payload_len) != FR_SUCC)
        goto ERROR;

    //req解析
    i_ret = __req_parse(p_st_private->p_req_packet, p_st_private, p_st_private->p_st_body_data_req, p_st_conn);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto ERROR;
    if (i_ret == APM_L7_ANALYZE_TODO)
    {
        frreport_body_free(&p_st_private->p_st_body_data_req);
        bytebuff_rewind(p_st_private->p_req_packet);
        return i_ret;
    }

    if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
        goto ERROR;

    //ResponseRequired
    if (frreport_body_l7_add_int(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
        goto ERROR;

    //start time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_l4_trans->st_request_time_first_byte) == FR_FAIL)
        goto ERROR;

    //st_request_time
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    ul_tmp = frtime_diff(&(p_st_l4_trans->st_request_time_first_byte), &(p_st_l4_trans->st_request_time));
    //send_time_us
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //request bytes
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_l4_trans->l_request_bytes) == FR_FAIL)
        goto ERROR;

    //end time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_l4_trans->st_request_time) == FR_FAIL)
        goto ERROR;

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
    if (p_st_report_data == NULL)
        goto ERROR;

    //拷贝相关链表
    p_st_private->p_lst_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_private->p_st_body_data_req);
    if (p_st_private->p_lst_comm == NULL)
        goto ERROR;

    p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
    if (p_st_private->p_lst_req == NULL)
        goto ERROR;

    if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
        goto ERROR;
    p_st_private->p_st_body_data_req = NULL;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;
    p_st_report_data = NULL;

    return i_ret;

ERROR:
    if (p_st_report_data)
        frreport_data_free(&p_st_report_data);
    __memcached_session_reset((void *)(p_st_private));
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * memcached的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet       (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 * \param p_st_session       (私有数据)
 *
 * \return APM_L7_ANALYZE_SUCC   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
FR_STATIC int __resp_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    unsigned long ul_tmp = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_memcached_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data* p_st_report_data = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL || p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private = (L7session_memcached_private*)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if (p_st_private->p_st_body_data_resp == NULL)
    {
        //创建数据链表
        p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if (p_st_private->p_st_body_data_resp == NULL)
            goto ERROR;

        if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 && p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
        {
            p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
            p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;
        }

        //创建bytebuff
        if (p_st_private->p_resp_packet == NULL)
        {
            p_st_private->p_resp_packet = bytebuff_creat();
            if (p_st_private->p_resp_packet == NULL)
                goto ERROR;
        }
    }
    /* 请求的字节数 */
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

    if (p_st_private->p_resp_packet == NULL)
        goto ERROR;
    //把这个包的数据先全加进bytebuff里
    if (bytebuff_add(p_st_private->p_resp_packet, p_st_packet->p_payload, p_st_packet->ui_payload_len) != FR_SUCC)
        goto ERROR;

    //resp解析
    i_ret = __resp_parse(p_st_private->p_resp_packet, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
    if (i_ret == APM_L7_ANALYZE_FAIL)
        goto ERROR;
    if (i_ret == APM_L7_ANALYZE_TODO)
    {
        frreport_body_free(&p_st_private->p_st_body_data_resp);
        p_st_private->p_st_body_data_resp=NULL;
        bytebuff_rewind(p_st_private->p_resp_packet);
        return i_ret;
    }

    //数据上报
    if (p_st_l4_trans->st_request_time_first_byte.tv_sec != 0)
    {
        FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req);
        FRREPORT_BODY_L7LIST_SET_COMM(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_comm);
        p_st_private->p_lst_req = NULL;
        p_st_private->p_lst_comm = NULL;
    }
    else
    {
        if (frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn) == FR_FAIL)
           goto ERROR;
    }

    //start time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_l4_trans->st_response_time_first_byte) == FR_FAIL)
        goto ERROR;

    if (p_st_l4_trans->st_request_time.tv_sec != 0 || p_st_l4_trans->st_request_time.tv_usec != 0)
    {
        //server time
        ul_tmp = frtime_diff(&(p_st_l4_trans->st_request_time), &(p_st_l4_trans->st_response_time_first_byte));
        if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;
    }
    else
    {
        if (frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, 0) == FR_FAIL)
            goto ERROR;
    }

    //st_response_time
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
        goto ERROR;

    //down load time
    ul_tmp = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &(p_st_l4_trans->st_response_time));
    if (frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
        goto ERROR;

    //end time
    if (frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
        goto ERROR;

    p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
    if (p_st_report_data == NULL)
        goto ERROR;

    if (frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
        goto ERROR;
    p_st_private->p_st_body_data_resp = NULL;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
        goto ERROR;
    p_st_report_data = NULL;

    memcached_session_destroy((void *)(p_st_private));
    p_st_session->p_session_private = NULL;

    return i_ret;

ERROR:
    if (p_st_report_data)
        frreport_data_free(&p_st_report_data);
    memcached_session_destroy((void *)(p_st_private));
    p_st_session->p_session_private = NULL;
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * memcached的packet解析
 *
 * \param p_st_conn          (入力链接信息)
 * \param p_st_packet       (入力packet信息)
 * \param p_st_hash_report   (保存Frreport_data)
 *
 * \return APM_L7_ANALYZE_SUCC   成功\n
 *         APM_L7_ANALYZE_FAIL   失败
 *
 * \note
 *
 */
int memcached_analysis(Conntrack *p_st_conn
                  , Apm_packet *p_st_packet
                  , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;

    if (p_st_conn == NULL || p_st_packet == NULL || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //fin syn 包  销毁私有数据
    if (p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        memcached_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //p_session_private   分配内存
    if (p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __memcached_private_create();
        //内存分配失败
        if (p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    //request
    if (p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        i_ret = __req_data_analysis(p_st_conn,p_st_packet,p_st_hash_report,p_st_session);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }
    //response
    else
    {
        i_ret = __resp_data_analysis(p_st_conn,p_st_packet,p_st_hash_report, p_st_session);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }

ERROR:
    if (p_st_session->p_session_private)
        memcached_session_destroy(p_st_session->p_session_private);
    p_st_session->p_session_private = NULL;
    return APM_L7_ANALYZE_FAIL;
}

/*!
 * 私有信息销毁
 *
 * \param p_private_session  (memcached的私有session数据)
 *
 * \return FR_SUCC   成功\n
 *
 * \note
 *
 */
int memcached_session_destroy(void *p_private_session)
{
    L7session_memcached_private *p_st_private = (L7session_memcached_private*)p_private_session;

    if (p_st_private)
    {
        if (p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if (p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if (p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if (p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if (p_st_private->p_req_packet)
            bytebuff_free(&p_st_private->p_req_packet);

        if (p_st_private->p_resp_packet)
            bytebuff_free(&p_st_private->p_resp_packet);

        p_st_private->i_sign_stats = 0;
        p_st_private->i_sign_gets = 0;
        p_st_private->i_sign_get = 0;

        frfree(p_st_private);
    }
    return FR_SUCC;
}
